<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Шаблонизатор
 * Переопределяет стандартный одноименный классы
 * 
 * @package CoreFramework
 * @version 1.0
 * @author Gennadiy Kozlenko
 */
class CI_Parser {
   
   /**
    * Instance
    *
    * @access private
    * @var object
    */
   var $_obj = null;
   
   /**
    * Левый ограничитель тегов
    *
    * @access private
    * @var string
    */
   var $_l_delim = '{%';
   
   /**
    * Правый ограничитель тегов
    *
    * @access private
    * @var string
    */
   var $_r_delim = '%}';
   
   /**
    * Массив загруженных модулей
    *
    * @access private
    * @var array
    */
   var $_modules = array();
   
   /**
    * Конструктор класса
    *
    * @access public
    * @return CI_Parser
    */
   function CI_Parser() {
      $this->_obj =& get_instance();
   } // end CI_Parser
   
   /**
    * Установка ограничителей тегов
    *
    * @access public
    * @param string $l_delim
    * @param string $r_delim
    */
   function set_delimiters($l_delim, $r_delim) {
      $this->_l_delim = $l_delim;
      $this->_r_delim = $r_delim;
   } // end set_delimiters
   
   /**
    * Обработка шаблона
    *
    * @access public
    * @param string $template
    * @param array $data
    * @param boolean $return
    * @return string
    */
   function parse($template, $data, $return = false) {
      $output = $this->_load_template($template);
      if (!empty($output)) {
         foreach ($data as $key => $val) {
            if (is_array($val)) {
               $output = $this->_parse_pair($key, $val, $output);
            } else {
               $output = $this->_parse_single($key, $val, $output);
            }
         }
      }
      if (false === $return) {
         $this->_obj->output->final_output = $output;
      }
      return $output;
   } // end parse
   
   /**
    * Загрузка шаблона
    * Так же происходит обработка мета-тегов
    * В будущем нужно переписать с использованием компиляции шаблоноа
    *
    * @access private
    * @param string $template
    * @return string
    */
   function _load_template($template) {
      $output = $this->_obj->load->view($this->_obj->config->item('language') . '/' . $template, array(), true);
      // Обрабатываем шаблон и заменяем все мета-теги
      $matches = array();
      if (preg_match_all('~{%([a-z0-9_]+)\[([^\]]+)\]%}~s', $output, $matches)) {
         for ($i = 0; $i < count($matches[0]); $i++) {
            if (false !== ($meta = $this->_parse_meta($matches[1][$i], $matches[2][$i]))) {
               $output = preg_replace('~' . preg_quote($matches[0][$i], '~') . '~', $meta, $output, 1);
            }
         }
      }
      return $output;
   } // end _load_template
   
   /**
    * Замена одиночного тега
    *
    * @access private
    * @param string $key
    * @param mixed $val
    * @param string $output
    * @return string
    */
   function _parse_single($key, $val, $output) {
      return str_replace($this->_l_delim . $key . $this->_r_delim, $val, $output);
   } // end _parse_single
   
   /**
    * Замена парных тегов
    *
    * @access private
    * @param string $key
    * @param array $data
    * @param string $output
    * @return string
    */
   function _parse_pair($key, $data, $output) {
   	$matches = array();
      if (preg_match_all('~' . preg_quote($this->_l_delim . $key . $this->_r_delim) . '(.+?)' . preg_quote($this->_l_delim . '/' . $key . $this->_r_delim) . '~s', $output, $matches)) {
         for ($i = 0; $i < count($matches[0]); $i++) {
            $items = '';
            foreach ($data as $row) {
               if (is_array($row)) {
                  $item = $matches[1][$i];
                  foreach ($row as $k => $v) {
                     if (is_string($v) || is_numeric($v)) {
                        $item = $this->_parse_single($k, $v, $item);
                     } elseif (is_array($v)) {
                        $item = $this->_parse_pair($k, $v, $item);
                     }
                  }
                  $items .= $item;
               }
            }
            $output = str_replace($matches[0][$i], $items, $output);
         }
      }
      return $output;
   } // end _parse_pair
   
   /**
    * Получение значения мета-тега
    *
    * @access private
    * @param string $name
    * @param string $value
    * @return string
    */
   function _parse_meta($name, $value) {
      $output = false;
      if (!in_array($name, $this->_modules)) {
         if (file_exists(APPPATH . 'helpers/parser/' . $name . '_helper.php')) {
            $this->_obj->load->helper('parser/' . $name);
            array_push($this->_modules, $name);
         } else {
            return $output;
         }
      }
      $method = $name . '_process';
      if (is_callable($method)) {
         $output = call_user_func_array($method, array($value));
      }
      return $output;
   } // end _parse_meta
   
}
